//
//  main.cpp
//  智能指针
//
//  Created by 卜绎皓 on 2022/12/23.
//
#include<iostream>
#include<memory>
#include<mutex>
using namespace std;


namespace byih
{
    //auto_ptr 的模拟实现
    template<class T>
    class auto_ptr
    {
    public:
        auto_ptr(T* ptr)
            :_ptr(ptr)
        {
            
        }
        
        auto_ptr(auto_ptr<T>& sp)
            :_ptr(sp.ptr)
        {
            //管理权限转移
            sp._ptr = nullptr;
        }
        
        auto_ptr<T>& operator = (auto_ptr<T>& ap)
        {
            //检测是否为自己赋值
            if(this != &ap)
            {
                //释放当前对象中资源
                if(_ptr)
                    delete _ptr;
                
                //转移ap中资源到当前对象中
                _ptr = ap._ptr;
                ap._ptr = nullptr;
            }
            
            return *this;
        }
        
        ~auto_ptr()
        {
            if(_ptr)
            {
                delete _ptr;
            }
        }
        
        //像指针一样使用
        T& operator*()
        {
            return *_ptr;
        }
        
        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
    };

    //unique_ptr的模拟实现
    template<class T>
    class unique_ptr
    {
    public:
        unique_ptr(T* ptr)
            :_ptr(ptr)
        {
            
        }
        
        ~unique_ptr()
        {
            if(_ptr)
                delete _ptr;
        }
        
        //像指针一样使用
        T& operator*()
        {
            return *_ptr;
        }
        
        T* operator->()
        {
            return _ptr;
        }
        
        unique_ptr(const unique_ptr<T>& sp) = delete;
        unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;
    private:
        T* _ptr;
    };

    //shared_ptr的模拟实现
    template<class T>
    class shared_ptr
    {
    public:
        shared_ptr(T* ptr = nullptr)
            :_ptr(ptr)
            ,_pRefCount(new int(1))
            ,_pmtx(new mutex)
        {
            
        }
        
        shared_ptr(const shared_ptr<T>& sp)
            :_ptr(sp._ptr)
            ,_pRefCount(sp._pRefCount)
            ,_pmtx(sp._pmtx)
        {
            AddRef();
        }
        
        void Release()
        {
            _pmtx->lock();
            
            bool flag = false;
            
            if(--(*_pRefCount) == 0 && _ptr)
            {
                delete _ptr;
                delete _pRefCount;
                
                flag = true;
            }
            
            _pmtx->unlock();
            
            if(flag == true)
            {
                delete _pmtx;
            }
            
        }
        
        void AddRef()
        {
            _pmtx->lock();
            
            ++(*_pRefCount);
            
            _pmtx->unlock();
        }
        
        shared_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
            if(_ptr != sp._ptr)
            {
                Release();
                _ptr = sp._ptr;
                _pRefCount = sp._pRefCount;
                _pmtx = sp._pmtx;
                AddRef();
            }
            
            return *this;
        }
        
        int use_count()
        {
            return *_pRefCount;
        }
        
        ~shared_ptr()
        {
            Release();
        }
        
        //像指针一样使用
        T& operator*()
        {
            return *_ptr;
        }
        
        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
        int* _pRefCount;
        mutex* _pmtx;
    };


    //简化版本weak_ptr实现
    template<class T>
    class weak_ptr
    {
    public:
        weak_ptr()
            :_ptr(nullptr)
        {
            
        }
        
        weak_ptr(const shared_ptr<T>& sp)
            :_ptr(sp.get())
        {
            
        }
        
        weak_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
            _ptr = sp.get();
            
            return *this;
        }
        
        T& operator*()
        {
            return *_ptr;
        }
        
        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
    };
}


